/*
 * Copyright 2008, 2009 Kobi Krasnoff
 * 
 * This file is part of "Catch Falling Coins".
 *
 * "Catch Falling Coins" is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * "Catch Falling Coins" is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with "Catch Falling Coins".  If not, see <http://www.gnu.org/licenses/>.
 *
 */

import java.io.InputStream;

import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.game.GameCanvas;
import javax.microedition.lcdui.game.TiledLayer;
import javax.microedition.media.Manager;
import javax.microedition.media.Player;
import javax.microedition.media.PlayerListener;
import javax.microedition.lcdui.CommandListener;
import java.util.*;

public class MainScreenCanvas extends GameCanvas implements Runnable, CommandListener, PlayerListener {
	private MainMIDlet parent;
	private Image imgBackgound = null;
	int imgBackgoundX = 0, imgBackgoundY = 0;
	Player player, playerExplode, playerYeah;
	GripeSprite gripeSprite;
	Vector basicObjectSpriteVector = new Vector();
	Vector explosionSpriteVector = new Vector();
	int counter = 0;
	InputStream isExplode, isYeah;
	Image scoreImage;
    private int totalScore = 0;
    private int numofLives = 3;
    private TiledLayer scoreLayer;
    private TiledLayer numofLivesLayer;
    private Image numofLivesImage;
    private Thread t;
    private CreateObject createObject;
    private Command menuCommand = new Command("Go to Menu", Command.EXIT, 1);
    private boolean runMode = false;
	
	public MainScreenCanvas(MainMIDlet parent)
	{
		super(true);
		this.parent = parent;
		//scoreLayer = new TiledLayer();
		addCommand(menuCommand);
		setCommandListener(this);
		
		try
		{
			imgBackgound = Image.createImage("/images/area03_bkg0.png");
			imgBackgoundX = this.getWidth() - imgBackgound.getWidth();
			imgBackgoundY = this.getHeight() - imgBackgound.getHeight();
		}
		catch(Exception e)
		{
			System.out.println(e.getMessage());
		}
		
		gripeSprite = new GripeSprite(imgBackgound);
		gripeSprite.setPosition(0, this.getHeight() - 32);
		gripeSprite.setScreenWidth(this.getWidth());
		
		isExplode = getClass().getResourceAsStream("/sounds/explosion.wav");
		try
		{
			playerExplode = Manager.createPlayer(isExplode, "audio/x-wav");
			playerExplode.setLoopCount(1);
			playerExplode.prefetch();
		}
		catch(Exception e)
		{
			System.out.println(e.getMessage());
		}
		
		isYeah = getClass().getResourceAsStream("/sounds/YEAH1.wav");
		try
		{
			playerYeah = Manager.createPlayer(isYeah, "audio/x-wav");
			playerYeah.setLoopCount(1);
			playerYeah.prefetch();
		}
		catch(Exception e)
		{
			System.out.println(e.getMessage());
		}
		
		try
		{
			scoreImage = Image.createImage("/images/kromasky_16x16.png");
		}
		catch(Exception e)
		{
			System.out.println(e.getMessage());
		}
		
		try
		{
			numofLivesImage = Image.createImage("/images/gem_80_points.png");
		}
		catch(Exception e)
		{
			System.out.println(e.getMessage());
		}
	}
	
	public void commandAction(Command c, Displayable d) {
		if (c == menuCommand) {
            parent.setCurrent("MainList");
        }
	}
	
	/**
	 * starts thread
	 */
	public void start()
	{
		runMode = true;
		t = new Thread(this);
		t.start();
		createObject = new CreateObject();
		createObject.start();
		play();
	}
	
	/**
	 * stops thread
	 */
	public void stop()
	{
		runMode = false;
		try
		{
			player.stop();
			parent.addContinue();
		}
		catch(Exception e)
		{
			System.out.println(e.getMessage());
		}
	}
	
	public void play()
	{
		try
		{
			InputStream is = getClass().getResourceAsStream("/sounds/HAVANAGI.mid");
			player = Manager.createPlayer(is, "audio/midi");
			player.setLoopCount(-1);
			player.prefetch();
			player.start();
		}
		catch(Exception e)
		{
			System.out.println(e.getMessage());
		}
	}
	
	public void playExplosion()
	{
		try
		{
			playerExplode.start();
		}
		catch(Exception e)
		{
			System.out.println(e.getMessage());
		}
	}
	
	public void playYeah()
	{
		try
		{
			playerYeah.start();
		}
		catch(Exception e)
		{
			System.out.println(e.getMessage());
		}
	}
	
	public void run()
	{
		Graphics g = getGraphics();
		play();
		while (runMode)
		{
			tick();
			input();
			render(g);
			try 
			{
				Thread.sleep(1);
			}
			catch (InterruptedException e) {}
			
		}
	}
	
	private void addToExplosionVector(Vector v, BasicObjectSprite b)
	{
		BasicObjectSprite b2 = BasicObjectSpriteFactory.returnObject(BasicObjectSpriteFactory.EXPLOSION_SPRITE);
		b2.setPosition(b.getX() - 24, b.getY() - 48);
		v.addElement(b2);
	}
	
	/**
	 * responsible for object movements
	 */
	private void tick()
	{
		synchronized(this)
		{
			// handles falling objects
			BasicObjectSprite b;
			for(int i=0; i<basicObjectSpriteVector.size(); i++)
			{
				// basic fall
				b = (BasicObjectSprite)basicObjectSpriteVector.elementAt(i);
				b.fall();
				b.nextFrame();
				basicObjectSpriteVector.setElementAt(b, i);
				
				// detect collision
				if(b.collidesWith(gripeSprite, false))
				{
					basicObjectSpriteVector.removeElementAt(i);
					if (b.returnBasicObjectSpriteType() != BasicObjectSpriteFactory.BOMB_SPRITE)
					{
						playYeah();
						if (b.returnBasicObjectSpriteType() == BasicObjectSpriteFactory.GOLDCOIN_SPRITE)
						{
							totalScore += 20;
						}
						else if (b.returnBasicObjectSpriteType() == BasicObjectSpriteFactory.SILVERCOIN_SPRITE)
						{
							totalScore += 10;
						}
					}
					else
					{
						addToExplosionVector(explosionSpriteVector, b);
						numofLives--;
					}
					System.out.println(totalScore);
				}
				// detect touch the ground
				else if (b.getY() == this.getHeight() - 16)
				{
					b.endFall();
					if (b.returnBasicObjectSpriteType() == BasicObjectSpriteFactory.BOMB_SPRITE)
					{
						addToExplosionVector(explosionSpriteVector, b);
					}
					basicObjectSpriteVector.removeElementAt(i);
				}
			}
			
			// handles explosions
			BasicObjectSprite b2;
			for(int i=0; i<explosionSpriteVector.size(); i++)
			{
				b2 = (BasicObjectSprite)explosionSpriteVector.elementAt(i);
				b2.nextFrame();
				if (b2.getFrame() >= b2.getRawFrameCount() - 1)
				{
					explosionSpriteVector.removeElementAt(i);
					playExplosion();
				}
			}
			
			// handles counter
			counter++;
			if (counter > 10)
				counter = 0;
			
			if (numofLives <= 0)
			{
				parent.setCurrent("GameOver");
			}
				
		}
		
	}
	
	/**
	 * response to key input
	 */
	private void input()
	{
		int keyStates = getKeyStates();
		if ((keyStates & LEFT_PRESSED) != 0)
		{
			gripeSprite.moveLeft();
		}
		else if ((keyStates & RIGHT_PRESSED) != 0)
		{
			gripeSprite.moveRight();
		}
		else if (keyStates == 0)
		{
			gripeSprite.moveStand();
		}
		
	}
	
	/**
	 * Responsible for the drawing
	 * @param g
	 */
	private void render(Graphics g)
	{
		synchronized(this)
		{
			BasicObjectSprite b;
			g.drawImage(imgBackgound, imgBackgoundX, imgBackgoundY, Graphics.TOP | Graphics.LEFT);
			gripeSprite.paint(g);
			for(int i=0; i<basicObjectSpriteVector.size(); i++)
			{
				b = (BasicObjectSprite)basicObjectSpriteVector.elementAt(i);
				b.paint(g);
			}
			for (int i=0; i<explosionSpriteVector.size(); i++)
			{
				b = (BasicObjectSprite)explosionSpriteVector.elementAt(i);
				b.paint(g);
			}
			
			scoreLayer = createScore(totalScore);
			scoreLayer.paint(g);
			
			numofLivesLayer = createNumOfLivesLayer(numofLives);
			numofLivesLayer.setPosition(this.getWidth() - 48, 0);
			numofLivesLayer.paint(g);
		}
		this.flushGraphics();
	}
	
	private TiledLayer createNumOfLivesLayer(int numofLives)
	{
		TiledLayer tiledLayer = new TiledLayer(3, 1, numofLivesImage, 16, 16);
		
		for (int i=0; i<3; i++)
		{
			if (i < numofLives)
				tiledLayer.setCell(i, 0, 1);
			else
				tiledLayer.setCell(i, 0, 0);
			
		}
		
		return tiledLayer;
	}
	
	private TiledLayer createScore(int num)
	{
		TiledLayer tiledLayer = new TiledLayer(59, 1, scoreImage, 16, 16);
		
		String str = String.valueOf(num);
		char[] cArray = str.toCharArray();
		for (int i=0; i<cArray.length; i++)
		{
			tiledLayer.setCell(i, 0, (int)cArray[i] - 31);
		}
		
		return tiledLayer;
	}
	
	private int generateRandom(int min, int max)
	{
		Random gen = new Random();
		gen.setSeed(System.currentTimeMillis());
		float f = gen.nextFloat();
		return (int)(min + f * (max - min + 1));
	}
	
	private void addToVector(int typeOfVector)
	{
		BasicObjectSprite b = BasicObjectSpriteFactory.returnObject(typeOfVector);
		b.setPosition(generateRandom(0, this.getWidth() - 32), 0);
		synchronized(this)
		{
			basicObjectSpriteVector.addElement(b);
		}
		
	}
	
	private class CreateObject extends Thread
	{
		private int interval = 1;
		
		public void run()
		{
			while(runMode)
			{
				int objectType = counter % 3 + 2;
				addToVector(objectType);
				interval = generateRandom(300, 1500);
				try 
				{
					Thread.sleep(interval);
				}
				catch (InterruptedException e) {}
			}
		}
	}
	
	public void hideNotify()
	{
		stop();
	}
	
	public void showNotify()
	{
		start();
	}
	
	public void setInitValues()
	{
		totalScore = 0;
		numofLives = 3;
		runMode = false;
		basicObjectSpriteVector.removeAllElements();
		explosionSpriteVector.removeAllElements();
	}
	
	public void playerUpdate(Player p, String str, Object obj)
	{
		
	}
}
